package cn.jingyuan.bee.utils.map;

import cn.jingyuan.bee.utils.ArrayUtils;
import cn.jingyuan.bee.utils.ObjectUtils;
import cn.jingyuan.bee.utils.ReflectUtils;
import cn.jingyuan.bee.utils.StringUtils;
import cn.jingyuan.bee.utils.collection.CollectionUtils;
import cn.jingyuan.bee.utils.convert.Convert;
import cn.jingyuan.bee.utils.lang.Editor;
import cn.jingyuan.bee.utils.lang.Filter;
import cn.jingyuan.bee.utils.lang.TypeReference;

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Map 相关工具类
 */
public class MapUtils {

    /** 默认初始大小 */
    public static final int DEFAULT_INITIAL_CAPACITY = 16;

    /** 默认增长因子，当 Map 的 size 达到 容量*增长因子时，开始扩充 Map */
    public static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * Map 是否为空
     *
     * @param map 集合
     *
     * @return 是否为空
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return null == map || map.isEmpty();
    }

    /**
     * Map 是否为非空
     *
     * @param map 集合
     *
     * @return 是否为非空
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return null != map && !map.isEmpty();
    }

    /**
     * 如果提供的集合为 {@code null}，返回一个不可变的默认空集合，否则返回原集合<br>
     * 空集合使用 {@link Collections#emptyMap()}
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param set 提供的集合，可能为 null
     *
     * @return 原集合，若为 null 返回空集合
     */
    public static <K, V> Map<K, V> emptyIfNull(Map<K, V> set) {
        return (null == set) ? Collections.emptyMap() : set;
    }

    /**
     * 如果给定 Map 为空，返回默认 Map
     *
     * @param <T> 集合类型
     * @param <K> 键类型
     * @param <V> 值类型
     * @param map Map
     * @param defaultMap 默认 Map
     *
     * @return 非空（empty）的原 Map 或默认 Map
     */
    public static <T extends Map<K, V>, K, V> T defaultIfEmpty(T map, T defaultMap) {
        return isEmpty(map) ? defaultMap : map;
    }

    /**
     * 新建一个 HashMap
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     *
     * @return HashMap 对象
     */
    public static <K, V> HashMap<K, V> newHashMap() {
        return new HashMap<>();
    }

    /**
     * 新建一个 HashMap
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param size 初始大小，由于默认负载因子 0.75，传入的 size 会实际初始大小为 size / 0.75 + 1
     * @param isOrder Map 的 Key 是否有序，有序返回 {@link LinkedHashMap}，否则返回 {@link HashMap}
     *
     * @return HashMap 对象
     */
    public static <K, V> HashMap<K, V> newHashMap(int size, boolean isOrder) {
        int initialCapacity = (int) (size / DEFAULT_LOAD_FACTOR) + 1;
        return isOrder ? new LinkedHashMap<>(initialCapacity) : new HashMap<>(initialCapacity);
    }

    /**
     * 新建一个 HashMap
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param size 初始大小，由于默认负载因子 0.75，传入的 size 会实际初始大小为 size / 0.75 + 1
     *
     * @return HashMap 对象
     */
    public static <K, V> HashMap<K, V> newHashMap(int size) {
        return newHashMap(size, false);
    }

    /**
     * 新建一个 HashMap
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param isOrder Map 的 Key 是否有序，有序返回 {@link LinkedHashMap}，否则返回 {@link HashMap}
     *
     * @return HashMap 对象
     */
    public static <K, V> HashMap<K, V> newHashMap(boolean isOrder) {
        return newHashMap(DEFAULT_INITIAL_CAPACITY, isOrder);
    }

    /**
     * 新建 TreeMap，Key 有序的 Map
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param comparator Key 比较器
     *
     * @return TreeMap
     */
    public static <K, V> TreeMap<K, V> newTreeMap(Comparator<? super K> comparator) {
        return new TreeMap<>(comparator);
    }

    /**
     * 新建 TreeMap，Key 有序的 Map
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param map Map
     * @param comparator Key 比较器
     *
     * @return TreeMap
     */
    public static <K, V> TreeMap<K, V> newTreeMap(Map<K, V> map, Comparator<? super K> comparator) {
        final TreeMap<K, V> treeMap = new TreeMap<>(comparator);
        if (!isEmpty(map)) {
            treeMap.putAll(map);
        }
        return treeMap;
    }

    /**
     * 创建键不重复 Map
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param size 初始容量
     *
     * @return {@link IdentityHashMap}
     */
    public static <K, V> Map<K, V> newIdentityMap(int size) {
        return new IdentityHashMap<>(size);
    }

    /**
     * 新建一个初始容量为 {@link MapUtils#DEFAULT_INITIAL_CAPACITY} 的 ConcurrentHashMap
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     *
     * @return ConcurrentHashMap
     */
    public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap() {
        return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
    }

    /**
     * 新建一个 ConcurrentHashMap
     *
     * @param size 初始容量，当传入的容量小于等于 0 时，容量为 {@link MapUtils#DEFAULT_INITIAL_CAPACITY}
     * @param <K> key 的类型
     * @param <V> value 的类型
     *
     * @return ConcurrentHashMap
     */
    public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(int size) {
        final int initCapacity = size <= 0 ? DEFAULT_INITIAL_CAPACITY : size;
        return new ConcurrentHashMap<>(initCapacity);
    }

    /**
     * 传入一个 Map 将其转化为 ConcurrentHashMap 类型
     *
     * @param map map
     * @param <K> key 的类型
     * @param <V> value 的类型
     *
     * @return ConcurrentHashMap
     */
    public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(Map<K, V> map) {
        if (isEmpty(map)) {
            return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
        }
        return new ConcurrentHashMap<>(map);
    }

    /**
     * 创建 Map<br>
     * 传入抽象 Map{@link AbstractMap} 和 {@link Map} 类将默认创建 {@link HashMap}
     *
     * @param <K> map 键类型
     * @param <V> map 值类型
     * @param mapType map 类型
     *
     * @return {@link Map} 实例
     */
    public static <K, V> Map<K, V> createMap(Class<?> mapType) {
        if (mapType.isAssignableFrom(AbstractMap.class)) {
            return new HashMap<>();
        } else {
            return (Map<K, V>) ReflectUtils.newInstance(mapType);
        }
    }

    /**
     * 将单一键值对转换为 Map
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param key 键
     * @param value 值
     *
     * @return {@link HashMap}
     */
    public static <K, V> HashMap<K, V> of(K key, V value) {
        return of(key, value, false);
    }

    /**
     * 将单一键值对转换为 Map
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param key 键
     * @param value 值
     * @param isOrder 是否有序
     *
     * @return {@link HashMap}
     */
    public static <K, V> HashMap<K, V> of(K key, V value, boolean isOrder) {
        final HashMap<K, V> map = newHashMap(isOrder);
        map.put(key, value);
        return map;
    }

    /**
     * 将数组转换为 Map（HashMap），支持数组元素类型为：
     *
     * <pre>
     * Map.Entry
     * 长度大于 1 的数组（取前两个值），如果不满足跳过此元素
     * Iterable 长度也必须大于 1（取前两个值），如果不满足跳过此元素
     * Iterator 长度也必须大于 1（取前两个值），如果不满足跳过此元素
     * </pre>
     *
     * <pre>
     * Map&lt;Object, Object&gt; colorMap = MapUtil.of(new String[][] { { "RED", "#FF0000" }, { "GREEN", "#00FF00" }, { "BLUE", "#0000FF" } });
     * </pre>
     * <p>
     * 参考：commons-lang
     *
     * @param array 数组。元素类型为 Map.Entry、数组、Iterable、Iterator
     *
     * @return {@link HashMap}
     */
    public static HashMap<Object, Object> of(Object[] array) {
        if (array == null) {
            return null;
        }
        final HashMap<Object, Object> map = new HashMap<>((int) (array.length * 1.5));
        for (int i = 0; i < array.length; i++) {
            Object object = array[i];
            if (object instanceof Map.Entry) {
                Entry entry = (Entry) object;
                map.put(entry.getKey(), entry.getValue());
            } else if (object instanceof Object[]) {
                final Object[] entry = (Object[]) object;
                if (entry.length > 1) {
                    map.put(entry[0], entry[1]);
                }
            } else if (object instanceof Iterable) {
                Iterator iter = ((Iterable) object).iterator();
                if (iter.hasNext()) {
                    final Object key = iter.next();
                    if (iter.hasNext()) {
                        final Object value = iter.next();
                        map.put(key, value);
                    }
                }
            } else if (object instanceof Iterator) {
                Iterator iter = ((Iterator) object);
                if (iter.hasNext()) {
                    final Object key = iter.next();
                    if (iter.hasNext()) {
                        final Object value = iter.next();
                        map.put(key, value);
                    }
                }
            } else {
                throw new IllegalArgumentException(StringUtils.format("Array element {}, '{}', is not type of Map.Entry or Array or Iterable or Iterator", i, object));
            }
        }
        return map;
    }

    /**
     * 行转列，合并相同的键，值合并为列表<br>
     * 将 Map 列表中相同 key 的值组成列表做为 Map 的 value<br>
     * 是 {@link #toMapList(Map)} 的逆方法<br>
     * 比如传入数据：
     *
     * <pre>
     * [
     *  {a: 1, b: 1, c: 1}
     *  {a: 2, b: 2}
     *  {a: 3, b: 3}
     *  {a: 4}
     * ]
     * </pre>
     * <p>
     * 结果是：
     *
     * <pre>
     * {
     *   a: [1,2,3,4]
     *   b: [1,2,3,]
     *   c: [1]
     * }
     * </pre>
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param mapList Map 列表
     *
     * @return Map
     */
    public static <K, V> Map<K, List<V>> toListMap(Iterable<? extends Map<K, V>> mapList) {
        final HashMap<K, List<V>> resultMap = new HashMap<>();
        if (CollectionUtils.isEmpty(mapList)) {
            return resultMap;
        }

        Set<Entry<K, V>> entrySet;
        for (Map<K, V> map : mapList) {
            entrySet = map.entrySet();
            K key;
            List<V> valueList;
            for (Entry<K, V> entry : entrySet) {
                key = entry.getKey();
                valueList = resultMap.get(key);
                if (null == valueList) {
                    valueList = CollectionUtils.newArrayList(entry.getValue());
                    resultMap.put(key, valueList);
                } else {
                    valueList.add(entry.getValue());
                }
            }
        }

        return resultMap;
    }

    /**
     * 列转行。将 Map 中值列表分别按照其位置与 key 组成新的 map。<br>
     * 是 {@link #toListMap(Iterable)} 的逆方法<br>
     * 比如传入数据：
     *
     * <pre>
     * {
     *   a: [1,2,3,4]
     *   b: [1,2,3,]
     *   c: [1]
     * }
     * </pre>
     * <p>
     * 结果是：
     *
     * <pre>
     * [
     *  {a: 1, b: 1, c: 1}
     *  {a: 2, b: 2}
     *  {a: 3, b: 3}
     *  {a: 4}
     * ]
     * </pre>
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param listMap 列表 Map
     *
     * @return Map 列表
     */
    public static <K, V> List<Map<K, V>> toMapList(Map<K, ? extends Iterable<V>> listMap) {
        final List<Map<K, V>> resultList = new ArrayList<>();
        if (isEmpty(listMap)) {
            return resultList;
        }

        boolean isEnd;// 是否结束。标准是元素列表已耗尽
        int index = 0;// 值索引
        Map<K, V> map;
        do {
            isEnd = true;
            map = new HashMap<>();
            List<V> vList;
            int vListSize;
            for (Entry<K, ? extends Iterable<V>> entry : listMap.entrySet()) {
                vList = CollectionUtils.newArrayList(entry.getValue());
                vListSize = vList.size();
                if (index < vListSize) {
                    map.put(entry.getKey(), vList.get(index));
                    if (index != vListSize - 1) {
                        // 当值列表中还有更多值（非最后一个），继续循环
                        isEnd = false;
                    }
                }
            }
            if (!map.isEmpty()) {
                resultList.add(map);
            }
            index++;
        } while (!isEnd);

        return resultList;
    }

    /**
     * 将已知 Map 转换为 key 为驼峰风格的 Map<br>
     * 如果 KEY 为非 String 类型，保留原值
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param map 原 Map
     *
     * @return 驼峰风格 Map
     */
    public static <K, V> Map<K, V> toCamelCaseMap(Map<K, V> map) {
        return (map instanceof LinkedHashMap) ? new CamelCaseLinkedMap<>(map) : new CamelCaseMap<>(map);
    }

    /**
     * 将键值对转换为二维数组，第一维是 key，第二纬是 value
     *
     * @param map map
     *
     * @return 数组
     */
    public static Object[][] toObjectArray(Map<?, ?> map) {
        if (map == null) {
            return null;
        }
        final Object[][] result = new Object[map.size()][2];
        if (map.isEmpty()) {
            return result;
        }
        int index = 0;
        for (Entry<?, ?> entry : map.entrySet()) {
            result[index][0] = entry.getKey();
            result[index][1] = entry.getValue();
            index++;
        }
        return result;
    }

    /**
     * 将 map 转成字符串
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param map Map
     * @param separator entry 之间的连接符
     * @param keyValueSeparator kv 之间的连接符
     * @param otherParams 其它附加参数字符串（例如密钥）
     *
     * @return 连接字符串
     */
    public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator, String... otherParams) {
        return join(map, separator, keyValueSeparator, false, otherParams);
    }

    /**
     * 根据参数排序后拼接为字符串，常用于签名
     *
     * @param params 参数
     * @param separator entry 之间的连接符
     * @param keyValueSeparator kv 之间的连接符
     * @param isIgnoreNull 是否忽略 null 的键和值
     * @param otherParams 其它附加参数字符串（例如密钥）
     *
     * @return 签名字符串
     */
    public static String sortJoin(Map<?, ?> params, String separator, String keyValueSeparator, boolean isIgnoreNull,
                                  String... otherParams) {
        return join(sort(params), separator, keyValueSeparator, isIgnoreNull, otherParams);
    }

    /**
     * 将 map 转成字符串，忽略 null 的键和值
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param map Map
     * @param separator entry 之间的连接符
     * @param keyValueSeparator kv 之间的连接符
     * @param otherParams 其它附加参数字符串（例如密钥）
     *
     * @return 连接后的字符串
     */
    public static <K, V> String joinIgnoreNull(Map<K, V> map, String separator, String keyValueSeparator, String... otherParams) {
        return join(map, separator, keyValueSeparator, true, otherParams);
    }

    /**
     * 将 map 转成字符串
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param map Map，为空返回 otherParams 拼接
     * @param separator entry 之间的连接符
     * @param keyValueSeparator kv 之间的连接符
     * @param isIgnoreNull 是否忽略 null 的键和值
     * @param otherParams 其它附加参数字符串（例如密钥）
     *
     * @return 连接后的字符串，map 和 otherParams 为空返回""
     */
    public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator, boolean isIgnoreNull, String... otherParams) {
        final StringBuilder strBuilder = StringUtils.builder();
        boolean isFirst = true;
        if (isNotEmpty(map)) {
            for (Entry<K, V> entry : map.entrySet()) {
                if (!isIgnoreNull || entry.getKey() != null && entry.getValue() != null) {
                    if (isFirst) {
                        isFirst = false;
                    } else {
                        strBuilder.append(separator);
                    }
                    strBuilder.append(Convert.toString(entry.getKey())).append(keyValueSeparator).append(Convert.toString(entry.getValue()));
                }
            }
        }
        // 补充其它字符串到末尾，默认无分隔符
        if (ArrayUtils.isNotEmpty(otherParams)) {
            for (String otherParam : otherParams) {
                strBuilder.append(otherParam);
            }
        }
        return strBuilder.toString();
    }

    /**
     * 过滤<br>
     * 过滤过程通过传入的 Editor 实现来返回需要的元素内容，这个 Editor 实现可以实现以下功能：
     *
     * <pre>
     * 1、过滤出需要的对象，如果返回 null 表示这个元素对象抛弃
     * 2、修改元素对象，返回集合中为修改后的对象
     * </pre>
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param map Map
     * @param editor 编辑器接口
     *
     * @return 过滤后的 Map
     */
    public static <K, V> Map<K, V> filter(Map<K, V> map, Editor<Entry<K, V>> editor) {
        if (null == map || null == editor) {
            return map;
        }

        final Map<K, V> map2 = ObjectUtils.clone(map);
        if (isEmpty(map2)) {
            return map2;
        }

        map2.clear();
        Entry<K, V> modified;
        for (Entry<K, V> entry : map.entrySet()) {
            modified = editor.edit(entry);
            if (null != modified) {
                map2.put(modified.getKey(), modified.getValue());
            }
        }
        return map2;
    }

    /**
     * 过滤<br>
     * 过滤过程通过传入的 Editor 实现来返回需要的元素内容，这个 Filter 实现可以实现以下功能：
     *
     * <pre>
     * 1、过滤出需要的对象，如果返回 null 表示这个元素对象抛弃
     * </pre>
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param map Map
     * @param filter 编辑器接口
     *
     * @return 过滤后的 Map
     */
    public static <K, V> Map<K, V> filter(Map<K, V> map, Filter<Entry<K, V>> filter) {
        if (null == map || null == filter) {
            return map;
        }

        final Map<K, V> map2 = ObjectUtils.clone(map);
        if (isEmpty(map2)) {
            return map2;
        }

        map2.clear();
        for (Entry<K, V> entry : map.entrySet()) {
            if (filter.accept(entry)) {
                map2.put(entry.getKey(), entry.getValue());
            }
        }
        return map2;
    }

    /**
     * 过滤 Map 保留指定键值对，如果键不存在跳过
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param map 原始 Map
     * @param keys 键列表
     *
     * @return Map 结果，结果的 Map 类型与原 Map 保持一致
     */
    public static <K, V> Map<K, V> filter(Map<K, V> map, K... keys) {
        final Map<K, V> map2 = ObjectUtils.clone(map);
        if (isEmpty(map2)) {
            return map2;
        }

        map2.clear();
        for (K key : keys) {
            if (map.containsKey(key)) {
                map2.put(key, map.get(key));
            }
        }
        return map2;
    }

    /**
     * Map 的键和值互换
     *
     * @param <T> 键和值类型
     * @param map Map 对象，键值类型必须一致
     *
     * @return 互换后的 Map
     */
    public static <T> Map<T, T> reverse(Map<T, T> map) {
        return filter(map, (Editor<Entry<T, T>>) t -> new Entry<T, T>() {

            @Override
            public T getKey() {
                return t.getValue();
            }

            @Override
            public T getValue() {
                return t.getKey();
            }

            @Override
            public T setValue(T value) {
                throw new UnsupportedOperationException("Unsupported setValue method !");
            }
        });
    }

    /**
     * 排序已有 Map，Key 有序的 Map，使用默认 Key 排序方式（字母顺序）
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param map Map
     *
     * @return TreeMap
     *
     * @see #newTreeMap(Map, Comparator)
     */
    public static <K, V> TreeMap<K, V> sort(Map<K, V> map) {
        return sort(map, null);
    }

    /**
     * 排序已有 Map，Key 有序的 Map
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param map Map，为 null 返回 null
     * @param comparator Key 比较器
     *
     * @return TreeMap，map 为 null 返回 null
     *
     * @see #newTreeMap(Map, Comparator)
     */
    public static <K, V> TreeMap<K, V> sort(Map<K, V> map, Comparator<? super K> comparator) {
        if (null == map) {
            return null;
        }

        TreeMap<K, V> result;
        if (map instanceof TreeMap) {
            // 已经是可排序 Map，此时只有比较器一致才返回原 map
            result = (TreeMap<K, V>) map;
            if (null == comparator || comparator.equals(result.comparator())) {
                return result;
            }
        } else {
            result = newTreeMap(map, comparator);
        }

        return result;
    }

    /**
     * 创建代理 Map<br>
     * {@link MapProxy} 对 Map 做一次包装，提供各种 getXXX 方法
     *
     * @param map 被代理的 Map
     *
     * @return {@link MapProxy}
     */
    public static MapProxy createProxy(Map<?, ?> map) {
        return MapProxy.create(map);
    }

    /**
     * 创建 Map 包装类 MapWrapper<br>
     * {@link MapWrapper} 对 Map 做一次包装
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param map 被代理的 Map
     *
     * @return {@link MapWrapper}
     */
    public static <K, V> MapWrapper<K, V> wrap(Map<K, V> map) {
        return new MapWrapper<>(map);
    }

    /**
     * 创建链接调用 map
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     *
     * @return map 创建类
     */
    public static <K, V> MapBuilder<K, V> builder() {
        return builder(new HashMap<>());
    }

    /**
     * 创建链接调用 map
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param map 实际使用的 map
     *
     * @return map 创建类
     */
    public static <K, V> MapBuilder<K, V> builder(Map<K, V> map) {
        return new MapBuilder<>(map);
    }

    /**
     * 创建链接调用 map
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param k key
     * @param v value
     *
     * @return map 创建类
     */
    public static <K, V> MapBuilder<K, V> builder(K k, V v) {
        return (builder(new HashMap<K, V>())).put(k, v);
    }

    /**
     * 获取 Map 的部分 key 生成新的 Map
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param map Map
     * @param keys 键列表
     *
     * @return 新 Map，只包含指定的 key
     */
    public static <K, V> Map<K, V> getAny(Map<K, V> map, final K... keys) {
        return filter(map, (Filter<Entry<K, V>>) entry -> ArrayUtils.contains(keys, entry.getKey()));
    }

    /**
     * 去掉 Map 中指定 key 的键值对，修改原 Map
     *
     * @param <K> Key 类型
     * @param <V> Value 类型
     * @param map Map
     * @param keys 键列表
     *
     * @return 修改后的 key
     */
    public static <K, V> Map<K, V> removeAny(Map<K, V> map, final K... keys) {
        for (K key : keys) {
            map.remove(key);
        }
        return map;
    }

    /**
     * 获取 Map 指定 key 的值，并转换为字符串
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static String getString(Map<?, ?> map, Object key) {
        return get(map, key, String.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 Integer
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Integer getInt(Map<?, ?> map, Object key) {
        return get(map, key, Integer.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 Double
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Double getDouble(Map<?, ?> map, Object key) {
        return get(map, key, Double.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 Float
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Float getFloat(Map<?, ?> map, Object key) {
        return get(map, key, Float.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 Short
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Short getShort(Map<?, ?> map, Object key) {
        return get(map, key, Short.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 Bool
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Boolean getBoolean(Map<?, ?> map, Object key) {
        return get(map, key, Boolean.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 Character
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Character getChar(Map<?, ?> map, Object key) {
        return get(map, key, Character.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 Long
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Long getLong(Map<?, ?> map, Object key) {
        return get(map, key, Long.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为 {@link Date}
     *
     * @param map Map
     * @param key 键
     *
     * @return 值
     */
    public static Date getDate(Map<?, ?> map, Object key) {
        return get(map, key, Date.class);
    }

    /**
     * 获取 Map 指定 key 的值，并转换为指定类型
     *
     * @param <T> 目标值类型
     * @param map Map
     * @param key 键
     * @param type 值类型
     *
     * @return 值
     */
    public static <T> T get(Map<?, ?> map, Object key, Class<T> type) {
        return null == map ? null : Convert.convert(type, map.get(key));
    }

    /**
     * 获取 Map 指定 key 的值，并转换为指定类型
     *
     * @param <T> 目标值类型
     * @param map Map
     * @param key 键
     * @param type 值类型
     *
     * @return 值
     */
    public static <T> T get(Map<?, ?> map, Object key, TypeReference<T> type) {
        return null == map ? null : Convert.convert(type, map.get(key));
    }

    /**
     * 重命名键<br>
     * 实现方式为一处然后重新 put，当旧的 key 不存在直接返回<br>
     * 当新的 key 存在，抛出 {@link IllegalArgumentException} 异常
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param map Map
     * @param oldKey 原键
     * @param newKey 新键
     *
     * @return map
     *
     * @throws IllegalArgumentException 新 key 存在抛出此异常
     */
    public static <K, V> Map<K, V> renameKey(Map<K, V> map, K oldKey, K newKey) {
        if (isNotEmpty(map) && map.containsKey(oldKey)) {
            if (map.containsKey(newKey)) {
                throw new IllegalArgumentException(StringUtils.format("The key '{}' exist !", newKey));
            }
            map.put(newKey, map.remove(oldKey));
        }
        return map;
    }

    /**
     * 去除 Map 中值为 {@code null} 的键值对<br>
     * 注意：此方法在传入的 Map 上直接修改。
     *
     * @param <K> key 的类型
     * @param <V> value 的类型
     * @param map Map
     *
     * @return map
     */
    public static <K, V> Map<K, V> removeNullValue(Map<K, V> map) {
        if (isEmpty(map)) {
            return map;
        }

        final Iterator<Entry<K, V>> iter = map.entrySet().iterator();
        Entry<K, V> entry;
        while (iter.hasNext()) {
            entry = iter.next();
            if (null == entry.getValue()) {
                iter.remove();
            }
        }

        return map;
    }

    /**
     * Map 包含 key
     *
     * @param map 集合
     *
     * @return true：包含，false：不包含
     */
    public static boolean containsKey(Map<?, ?> map, Object key) {
        boolean contains = isNotEmpty(map);
        if (contains) {
            return map.containsKey(key);
        } else {
            return false;
        }
    }

    /**
     * Map 不包含 key
     *
     * @param map 集合
     *
     * @return true：不包含，false：包含
     */
    public static boolean notContainsKey(Map<?, ?> map, Object key) {
        if (isEmpty(map)) {
            return true;
        }
        return !map.containsKey(key);
    }

}
